#include "WorldModelNode.h"

WorldModelNode::WorldModelNode()
{
	mNeedLoadOmittedInfo = true;
	m_RenderNode = NULL;

	InitialWorldModel();
}
WorldModelNode::~WorldModelNode()
{
 	if( m_RenderNode )
 	{
 		delete m_RenderNode;
 		m_RenderNode = NULL;
 	}
}
void WorldModelNode::Update( Predicate* root_p )
{
	ClearWorldModel();

	m_RenderNode = new RenderNode;
	HandleNode( root_p, m_RenderNode );

	//std::cout<<"m_RenderNode->Show()\n";
	//m_RenderNode->Show();
	//Show();
}
RenderNode* WorldModelNode::GetRenderNode()
{
	return m_RenderNode;
}
void WorldModelNode::LoadOmittedInfo( RenderNode* renderNode )
{
	//m_RenderNode->SetObj( renderNode->GetObj() );
	//m_RenderNode->SetScale( renderNode->GetScale() );
	//std::cout<< "set " << renderNode->GetObj() << "\n";
	CopyOmittedInfo( m_RenderNode, renderNode );

	for( unsigned int i = 0; i < renderNode->ChildNum(); i ++ )
	{
		RenderNode* rn = renderNode->GetChild( i );
		RenderNode* rc = m_RenderNode->GetChild( i );
		if( rn == NULL || rc == NULL )
		{
 			std::cerr << "(WorldModelNode) " << "Warning " << "LoadOmittedInfo\n";
 			std::cerr << m_RenderNode->ChildNum() << "\n";
 			std::cerr << renderNode->ChildNum() << "\n";
 			continue;
		}
		else
		{
			LoadOmittedInfo( rc, rn );
		}
	}
}
void WorldModelNode::LoadOmittedInfo( RenderNode* trgRenderNode, RenderNode* srcRenderNode )
{
// 	trgRenderNode->SetObj( srcRenderNode->GetObj() );
// 	trgRenderNode->SetScale( srcRenderNode->GetScale() );
	//std::cout<< "set " << srcRenderNode->GetObj() << "\n";
	CopyOmittedInfo( trgRenderNode, srcRenderNode );

	for( unsigned int i = 0; i < srcRenderNode->ChildNum(); i ++ )
	{
		RenderNode* rn = srcRenderNode->GetChild( i );
		RenderNode* rc = trgRenderNode->GetChild( i );
		if( rn == NULL || rc == NULL )
		{
 			std::cerr << "(WorldModelNode) ---" << "Warning " << "LoadOmittedInfo\n";
 			std::cerr << trgRenderNode->ChildNum() << "\n";
 			std::cerr << srcRenderNode->ChildNum() << "\n";
 			continue;
		}
		else
		{
			LoadOmittedInfo( rc, rn );
		}
	}
}
void WorldModelNode::CopyOmittedInfo( RenderNode* trgRenderNode, RenderNode* srcRenderNode )
{
	for( unsigned int i = 0; i < srcRenderNode->ChildNum(); i ++ )
	{
		RenderNode* rn = srcRenderNode->GetChild( i );
		RenderNode* rc = trgRenderNode->GetChild( i );

		if( !rc->m_SetTransform )
		{
			rc->SetTransform( rn->GetTransform() );
		}
		rc->SetObj( rn->GetObj() );
		rc->SetScale( rn->GetScale() );
		rc->ResetMaterials( rn->GetResetMaterials() );
	}
}
void WorldModelNode::Render()
{
	m_RenderNode->Paint();
}
std::string& WorldModelNode::Context()
{
	return m_context;
}
void WorldModelNode::InitialWorldModel()
{
	m_nodes.clear();
	
// 	int array_WM_size = sizeof(WM)/sizeof(std::string);
// 	for( int i = 0; i < array_WM_size; i ++ )
// 	{
// 		m_nodes.insert( std::make_pair(WM[i], WM_OneFloatAttr) );
// 	}

	m_nodes.insert( std::make_pair("time", WM_OneAttr) );
	m_nodes.insert( std::make_pair("BallRadius", WM_OneAttr) );
	m_nodes.insert( std::make_pair("FieldHeight", WM_OneAttr) );
	m_nodes.insert( std::make_pair("FieldLength", WM_OneAttr) );
	m_nodes.insert( std::make_pair("FieldWidth", WM_OneAttr) );
	m_nodes.insert( std::make_pair("FreeKickDistance", WM_OneAttr) );
	m_nodes.insert( std::make_pair("GoalDepth", WM_OneAttr) );
	m_nodes.insert( std::make_pair("GoalHeight", WM_OneAttr) );
	m_nodes.insert( std::make_pair("GoalWidth", WM_OneAttr) );
	m_nodes.insert( std::make_pair("score_left", WM_OneAttr) );
	m_nodes.insert( std::make_pair("score_right", WM_OneAttr) );
	m_nodes.insert( std::make_pair("team_left", WM_OneAttr) );
	m_nodes.insert( std::make_pair("team_right", WM_OneAttr) );

	m_nodes.insert( std::make_pair("nd", WM_ND) );

	//std::cout<< "(WorldModel) Registers " << m_nodes.size() << " nodes\n";
}
void WorldModelNode::ClearWorldModel()
{
	//m_nodes_oneDoubleAttr.clear();
}
void WorldModelNode::HandleNode( Predicate* p, RenderNode* renderNode  )
{
	NodeName name = p->name;
	WMTypeID type = NodeType(name);

 	if( type == WM_OneAttr )
 	{
 		HandleNodeOneAttr( p );
 	}
 	else if( type == WM_ND )
	{
		HandleNodeND( p, renderNode );

		for( std::multimap<std::string, Predicate*>::iterator chit = p->child.begin(); 
			chit != p->child.end(); chit ++ )
		{
			if( NodeType((*chit).second->name) == WM_ND )
			{
				RenderNode* rd = new RenderNode;
				renderNode->AddChild( rd );
				HandleNode( (*chit).second, rd );
			}
			else
			{
				HandleNode( (*chit).second, renderNode );
			}
		}
	}
}
WMTypeID WorldModelNode::NodeType( NodeName name )
{
	if( name == "nd" || name.empty() )
	{
		return WM_ND;
	}
	else if( m_nodes.find( name ) != m_nodes.end() )
	{
		return m_nodes[name];
	}
	else
	{
		return WM_NotDefined;
	}
}
void WorldModelNode::HandleNodeOneAttr( Predicate* p )
{
 	if( p->name == "team_left" || 
 		p->name == "team_right" )
 	{
 		std::string value;
 		p->GetValue( p->name, value );
 
 		m_nodes_oneStringAttr[p->name] = value;
 	}
	else
	{
		float value;
		p->GetValue( p->name, value );

		m_nodes_oneFloatAttr[p->name] = value;
	}
}
void WorldModelNode::HandleNodeND( Predicate* p, RenderNode* renderNode )
{
	for( std::multimap<std::string, Predicate*>::iterator chit = p->child.begin(); 
		chit != p->child.end(); chit ++ )
	{
		Predicate* child = (*chit).second;
		std::string name = child->name;

		if( name == "SLT" )
		{
			float transform[16];
			if( child->GetValue( name, transform, 16 ) )
			{
				renderNode->SetTransform( transform );
				renderNode->m_SetTransform = true;
			}
		}
		else if( name == "sSc" )
		{
			float scale[3];
			if( child->GetValue( name, scale, 3 ) )
			{
				renderNode->SetScale( scale );
			}
		}
		else if( name == "load" )
		{
			mNeedLoadOmittedInfo = false;
			std::string model;
			if( child->GetValue( name, model ) )
			{
				renderNode->SetObj( model );
			}
		}
		else if( name == "resetMaterials" )
		{
			std::vector<std::string> resetMatNames;
			if( child->GetValue( name, resetMatNames ) )
			{
				renderNode->ResetMaterials( resetMatNames );
			}
		}
		else if( name == "sMat" )
		{
			std::string sMatame;
			if( child->GetValue( name, sMatame ) )
			{
				renderNode->SetSMat( sMatame );
			}
		}
	}
}
float WorldModelNode::GetValueOneAttr( NodeName name )
{
 	if( m_nodes_oneFloatAttr.find( name ) != m_nodes_oneFloatAttr.end() )
 	{
 		return m_nodes_oneFloatAttr[name];
 	}
	else
	{
		return 0.0f;
	}
}
void WorldModelNode::Show()
{
	std::cout<< "----------------\n";
	for( std::map<NodeName,float>::iterator mit = m_nodes_oneFloatAttr.begin();
		mit != m_nodes_oneFloatAttr.end(); mit ++ )
	{
		std::cout<< (*mit).first << " " << (*mit).second << "\n";
	}
}
void WorldModelNode::SetTime( float time )
{
	m_nodes_oneFloatAttr[ "time" ] = time;
}
void WorldModelNode::SetNameTeamLeft( const std::string& name )
{
	m_nodes_oneStringAttr[ "team_left" ] = name;
}
void WorldModelNode::SetNameTeamRight( const std::string& name )
{
	m_nodes_oneStringAttr[ "team_right" ] = name;
}
void WorldModelNode::SetScoreLeft( float score )
{
	m_nodes_oneFloatAttr[ "score_left" ] = score;
}
void WorldModelNode::SetScoreRight( float score )
{
	m_nodes_oneFloatAttr[ "score_right" ] = score;
}
float WorldModelNode::Time()
{
	if( m_nodes_oneFloatAttr.find( "time" ) == m_nodes_oneFloatAttr.end() )
	{
		return 0.0;
	}

	return m_nodes_oneFloatAttr[ "time" ];
}
std::string WorldModelNode::NameTeamLeft()
{
 	if( m_nodes_oneStringAttr.find( "team_left" ) == m_nodes_oneStringAttr.end() )
 	{
		return std::string("");
 	}
 
 	return m_nodes_oneStringAttr[ "team_left" ];
}
std::string WorldModelNode::NameTeamRight()
{
 	if( m_nodes_oneStringAttr.find( "team_right" ) == m_nodes_oneStringAttr.end() )
 	{
 		return std::string("");
 	}
 
 	return m_nodes_oneStringAttr[ "team_right" ];
}

float WorldModelNode::ScoreTeamLeft()
{
	if( m_nodes_oneFloatAttr.find( "score_left" ) == m_nodes_oneFloatAttr.end() )
	{
		return 0.0;
	}

	return m_nodes_oneFloatAttr[ "score_left" ];
}
float WorldModelNode::ScoreTeamRight()
{
	if( m_nodes_oneFloatAttr.find( "score_right" ) == m_nodes_oneFloatAttr.end() )
	{
		return 0.0;
	}

	return m_nodes_oneFloatAttr[ "score_right" ];
}